#include "game.h"

#include <unistd.h>
#include <iostream>

using namespace std;

namespace {
    void InitTimerEvent(ev_timer *p_w, void(*cb)(struct ev_loop*, ev_timer*, int), void *data, double at, double repeat)
    {
        p_w->active = p_w->pending = 0;
        p_w->priority = 0;
        p_w->cb = cb;
        p_w->data = data;
        p_w->repeat = repeat;
        p_w->at = at;
    }

    void InitFdEvent(ev_io *p_w, void(*cb)(struct ev_loop*, ev_io*, int), void *data, int fd, int events)
    {
        p_w->active = p_w->pending = 0;
        p_w->priority = 0;
        p_w->cb = cb;
        p_w->data = data;
        p_w->fd = fd;
        p_w->events = events | EV__IOFDSET;
    }
}

Game::Game()
    : p_loop_(NULL)
    , right_answer_(-1)
    , remain_question_number_(5)
{
}

Game::~Game()
{
}

void Game::start(struct ev_loop *p_loop)
{
    p_loop_ = p_loop;
    InitTimerEvent(&timer_30sec_, Game::On30SecCallback, this, 30, 0);
    InitTimerEvent(&timer_20sec_, Game::On20SecCallback, this, 20, 0);
    InitTimerEvent(&timer_10sec_, Game::On10SecCallback, this, 10, 0);
    InitFdEvent(&stdin_read_event_, Game::OnStdinReadCallback, this, STDIN_FILENO, EV_READ);

    cout << "Welcome to Calculate GameLite." << endl
         << "You need answer 5 questions in 30 second. Each question has only 10 second." << endl
         << "Here we go!" << endl;

    srand(time(NULL));
    ev_timer_start(p_loop_, &timer_30sec_);
    ev_timer_start(p_loop_, &timer_20sec_);
    ev_io_start(p_loop_, &stdin_read_event_);

    askQuestion();
}

void Game::stop()
{
    ev_timer_stop(p_loop_, &timer_30sec_);
    ev_timer_stop(p_loop_, &timer_20sec_);
    ev_timer_stop(p_loop_, &timer_10sec_);
    ev_io_stop(p_loop_, &stdin_read_event_);
}

void Game::askQuestion()
{
    ev_timer_stop(p_loop_, &timer_10sec_);

    int a = random() % 100;
    int b = random() % 100;
    right_answer_ = a + b;
    cout << a << " + " << b << " = ? " << endl << "your answer: " << flush;

    --remain_question_number_;
    ev_timer_start(p_loop_, &timer_10sec_);
}

void Game::on30SecReach()
{
    cout << endl << "time is up, you fail!" << endl;
    ev_break(p_loop_, EVBREAK_ALL);
}

void Game::on20SecReach()
{
    cout << endl << "10 sec remain ..." << endl;
}

void Game::on10SecReach()
{
    cout << endl << "timeout. You fail!" << endl;
    ev_break(p_loop_, EVBREAK_ALL);
}

void Game::onStdinReadable()
{
    char input_buff[200];
    int rsize = read(STDIN_FILENO, input_buff, sizeof(input_buff));
    input_buff[rsize - 1] = '\0';

    int answer = atoi(input_buff);
    if (answer == right_answer_) {
        if (remain_question_number_ == 0) {
            cout << "Congratulation! You win." << endl;
            ev_break(p_loop_, EVBREAK_ALL);
        } else {
            askQuestion();
        }
    } else {
        cout << "wrong answer. You fail!" << endl;
        ev_break(p_loop_, EVBREAK_ALL);
    }
}

void Game::On30SecCallback(struct ev_loop *, ev_timer *p_w, int)
{
    Game *pthis = static_cast<Game*>(p_w->data);
    pthis->on30SecReach();
}

void Game::On20SecCallback(struct ev_loop *, ev_timer *p_w, int)
{
    Game *pthis = static_cast<Game*>(p_w->data);
    pthis->on20SecReach();
}

void Game::On10SecCallback(struct ev_loop *, ev_timer *p_w, int)
{
    Game *pthis = static_cast<Game*>(p_w->data);
    pthis->on10SecReach();
}

void Game::OnStdinReadCallback(struct ev_loop *, ev_io *p_w, int)
{
    Game *pthis = static_cast<Game*>(p_w->data);
    pthis->onStdinReadable();
}
